package com.space.components.token;

import com.auth0.jwt.interfaces.Claim;
import com.space.components.exception.Assert;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

/**
 * @author <a href="mailto:414563035@qq.com">Bedroom</a>
 * @date 2021/5/14 7:20 下午
 */
@Aspect
@Slf4j
public class TokenAspect {
    @Pointcut("@within(com.space.components.token.TokenParser) && execution(public * *(..))")
    public void pointcut() {
    }

    @Around(value = "pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        final HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String authorization = request.getHeader("Authorization");
        final Map<String, Claim> tokenParams = new HashMap<>();
        if (authorization != null) {
            final String token = authorization.replaceFirst("Bearer", "").trim();
            tokenParams.putAll(JWTUtil.verify(token).getClaims());
        }


        // 获取请求参数进行打印
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        final Parameter[] parameters = methodSignature.getMethod().getParameters();
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < parameters.length; i++) {
            for (Annotation annotation : parameters[i].getAnnotations()) {
                if (annotation instanceof TokenParam) {
                    Assert.notEmpty(tokenParams);
                    final String paramsName = parameters[i].getName();
                    final Class<?> clazz = parameters[i].getType();
                    final Object arg = tokenParams.get(paramsName).as(clazz);
                    log.debug("paramsName {} set {} type {}", paramsName, arg, clazz.getName());
                    args[i] = arg;
                    break;
                }
            }
        }

        return joinPoint.proceed(args);
    }
}
